﻿using ch10.binary;
using ch10.binary.type;

namespace ch10.interpreter
{
    public struct ControlStack
    {
        private ControlFrame[] _frames;

        public ControlStack(ControlFrame[] frames) : this()
        {
            _frames = frames;
        }

        internal void PushControlFrame(ref ControlFrame cf)
        {
            Math.Append(ref _frames, cf);
        }

        internal ControlFrame PopControlFrame()
        {
            var cf = _frames[^1];
            _frames = _frames[..^1];
            return cf;
        }

        public int ControlDepth()
        {
            return _frames.Length;
        }

        public ControlFrame TopControlFrame()
        {
            return _frames[^1];
        }

        internal (ControlFrame, int) TopCallFrame()
        {
            for (var n = _frames.Length - 1; n >= 0; n--)
            {
                var cf = _frames[n];
                if (cf.Opcode == OpCodes.Call)
                {
                    return (cf, _frames.Length - 1 - n);
                }
            }

            return (null, -1);
        }
    }

    public class ControlFrame
    {
        public readonly byte Opcode;
        public FuncType Bt; // block type
        public readonly Instruction[] Instrs; // expr
        public readonly int Bp; // base pointer (operand stack)
        public int Pc; // program counter

        public ControlFrame(byte opcode, ref FuncType bt, ref Instruction[] instrs, int bp)
        {
            Opcode = opcode;
            Bt = bt;
            Instrs = instrs;
            Bp = bp;
            Pc = 0;
        }
    }
}